package gis.sqlbase;

import java.sql.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * SQL 基本操作 通过它,可以很轻松的使用 JDBC 来操纵数据库
 *
 * @author
 */
public class SQLHelper {

    private static Logger logger = LoggerFactory.getLogger(DatabaseManage.class);
    /**
     * 数据库信息
     */
    private ConnectionInfor connectionInfor;

    /**
     * 初始化
     *
     * @param connectionInfor 数据库连接信息
     */
    public SQLHelper(ConnectionInfor connectionInfor) {
        this.connectionInfor = connectionInfor;
    }

    /**
     * 获取一个数据库连接 通过设置类的 driver / url / user / password 这四个静态变量来 设置数据库连接属性
     *
     * @return 数据库连接
     */
    public Connection getConnection() {
        try {
            // 获取驱动,这里使用的是 sqljdbc_282100_chs.exe,不同版本的驱动,语句有所不同
            Class.forName(connectionInfor.getDriver());
        } catch (ClassNotFoundException ex) {
            logger.error("获取驱动信息出错：" + connectionInfor.getDriver(), ex);
        }
        try {
            return DriverManager.getConnection(connectionInfor.getUrl(), connectionInfor.getUser(), connectionInfor.getPassword());
        } catch (SQLException ex) {
            logger.error("获取数据库连接出错：驱动：" + connectionInfor.getDriver() + " url:" + connectionInfor.getUrl() + " user:" + connectionInfor.getUser() + " password:" + connectionInfor.getPassword(), ex);
            return null;
        }
    }

    /**
     * 获取一个 Statement 该 Statement 已经设置数据集 可以滚动,可以更新
     *
     * @return 如果获取失败将返回 null,调用时记得检查返回值
     */
    public Statement getStatement() {
        Connection conn = getConnection();
        if (conn == null) {
            return null;
        }
        try {
            Statement statement = null;
            //测试
            if (connectionInfor.getDriver().equals("com.vertica.jdbc.Driver")) {
                statement = conn.createStatement();
            } else {
                statement = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            }
            //return conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

            return statement;
            // 设置数据集可以滚动,可以更新
        } catch (SQLException ex) {
            logger.error("获取Statement出错111222", ex);
            closeObject(conn);
        }
        return null;
    }

    /**
     * 获取一个 Statement 该 Statement 已经设置数据集 可以滚动,可以更新
     *
     * @param conn 数据库连接
     * @return 如果获取失败将返回 null,调用时记得检查返回值
     */
    public Statement getStatement(Connection conn) {
        if (conn == null) {
            return null;
        }
        try {
            return conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            // 设置数据集可以滚动,可以更新
        } catch (SQLException ex) {
            logger.error("获取Statement出错", ex);
            closeObject(conn);
            return null;
        }
    }

    /**
     * 获取一个带参数的 PreparedStatement 该 PreparedStatement 已经设置数据集 可以滚动,可以更新
     *
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return 如果获取失败将返回 null,调用时记得检查返回值
     */
    public PreparedStatement getPreparedStatement(String cmdText, Object... cmdParams) {
        logger.info(cmdText, cmdParams);
        Connection conn = getConnection();
        if (conn == null) {
            return null;
        }
        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(cmdText, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            int i = 1;
            for (Object item : cmdParams) {
                pstmt.setObject(i, item);
                i++;
            }
        } catch (SQLException e) {
            logger.error(cmdText, cmdParams);
            closeObject(conn);
            e.printStackTrace();
        }
        return pstmt;
    }

    /**
     * 获取一个带参数的 PreparedStatement 该 PreparedStatement 已经设置数据集 可以滚动,可以更新
     *
     * @param conn      数据库连接
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return 如果获取失败将返回 null,调用时记得检查返回值
     */
    public PreparedStatement getPreparedStatement(Connection conn, String cmdText, Object... cmdParams) {
        logger.info(cmdText, cmdParams);
        if (conn == null) {
            return null;
        }

        PreparedStatement pstmt = null;
        try {
            pstmt = conn.prepareStatement(cmdText, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
            int i = 1;
            for (Object item : cmdParams) {
                pstmt.setObject(i, item);
                i++;
            }
        } catch (SQLException e) {
            logger.error(cmdText, cmdParams);
            e.printStackTrace();
            closeObject(pstmt);
        }
        return pstmt;
    }

    /**
     * 执行 SQL 语句,返回结果为整型 主要用于执行非查询语句
     *
     * @param cmdText SQL 语句
     * @return 非负数:正常执行; -1:执行错误; -2:连接错误
     */
    public int ExecSql(String cmdText) {
        logger.info(cmdText);
        Statement stmt = getStatement();
        if (stmt == null) {
            return -2;
        }
        int i;
        try {
            i = stmt.executeUpdate(cmdText);
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            i = -1;
        } finally {
            close(stmt);
            // closeConnection(stmt);
        }
        return i;
    }

    /**
     * 执行 SQL 语句,返回结果为整型 主要用于执行非查询语句
     *
     * @param cmdText SQL 语句
     * @return 非负数:正常执行; -1:执行错误; -2:连接错误
     */
    public int ExecSql(Connection conn, String cmdText) {
        logger.info(cmdText);
        Statement stmt = getStatement(conn);
        if (stmt == null) {
            return -2;
        }
        int i;
        try {
            i = stmt.executeUpdate(cmdText);
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            i = -1;
        } finally {
            close(stmt);
        }
        return i;
    }

    /**
     * 执行 SQL 语句,返回结果为整型 主要用于执行非查询语句
     *
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return 非负数:正常执行; -1:执行错误; -2:连接错误
     */
    public int ExecSql(String cmdText, Object... cmdParams) {
        logger.info(cmdText, cmdParams);
        PreparedStatement pstmt = getPreparedStatement(cmdText, cmdParams);
        if (pstmt == null) {
            return -2;
        }
        int i;
        try {
            i = pstmt.executeUpdate();
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            i = -1;
        } finally {
            close(pstmt);
        }
        return i;
    }

    /**
     * 执行 SQL 语句,返回结果为整型 主要用于执行非查询语句
     *
     * @param conn      数据库连接
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return 非负数:正常执行; -1:执行错误; -2:连接错误
     */
    public int ExecSql(Connection conn, String cmdText, Object... cmdParams) {
        logger.info(cmdText, cmdParams);
        PreparedStatement pstmt = getPreparedStatement(conn, cmdText, cmdParams);
        if (pstmt == null) {
            return -2;
        }
        int i;
        try {
            i = pstmt.executeUpdate();
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            i = -1;
        } finally {
            close(pstmt);
        }
        return i;
    }

    /**
     * 返回结果集的第一行的一列的值,其他忽略
     *
     * @param cmdText SQL 语句
     * @return
     */
    public Object ExecScalar(String cmdText) {
        ResultSet rs = getResultSet(cmdText);
        Object obj = buildScalar(rs);
        close(rs);
        return obj;
    }

    /**
     * 返回结果集的第一行的一列的值,其他忽略
     *
     * @param conn    数据库连接
     * @param cmdText SQL 语句
     * @return
     */
    public Object ExecScalar(Connection conn, String cmdText) {
        ResultSet rs = getResultSet(conn, cmdText);
        Object obj = buildScalar(rs);
        close(rs);
        return obj;
    }

    /**
     * 返回结果集的第一行的一列的值,其他忽略
     *
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return
     */
    public Object ExecScalar(String cmdText, Object... cmdParams) {
        ResultSet rs = getResultSet(cmdText, cmdParams);
        Object obj = buildScalar(rs);
        close(rs);
        return obj;
    }

    /**
     * 返回结果集的第一行的一列的值,其他忽略
     *
     * @param conn      数据库连接
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return
     */
    public Object ExecScalar(Connection conn, String cmdText, Object... cmdParams) {
        ResultSet rs = getResultSet(conn, cmdText, cmdParams);
        Object obj = buildScalar(rs);
        close(rs);
        return obj;
    }

    /**
     * 返回一个 ResultSet
     *
     * @param cmdText SQL 语句
     * @return
     */
    public ResultSet getResultSet(String cmdText) {
        logger.info(cmdText);
        Statement stmt = getStatement();
        if (stmt == null) {
            return null;
        }
        try {
            return stmt.executeQuery(cmdText);
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            //closeConnection(stmt);
            close(stmt);
        }
        return null;
    }

    /**
     * 返回一个 ResultSet
     *
     * @param conn
     * @param cmdText SQL 语句
     * @return
     */
    public ResultSet getResultSet(Connection conn, String cmdText) {
        logger.info(cmdText);
        Statement stmt = getStatement(conn);
        if (stmt == null) {
            return null;
        }
        try {
            return stmt.executeQuery(cmdText);
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            closeObject(stmt);
        }
        return null;
    }

    /**
     * 返回一个 ResultSet
     *
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return
     */
    public ResultSet getResultSet(String cmdText, Object... cmdParams) {
        logger.info(cmdText, cmdParams);
        PreparedStatement pstmt = getPreparedStatement(cmdText, cmdParams);
        if (pstmt == null) {
            return null;
        }
        try {
            return pstmt.executeQuery();
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            closeConnection(pstmt);
        }
        return null;
    }

    /**
     * 返回一个 ResultSet
     *
     * @param conn      数据库连接
     * @param cmdText   需要 ? 参数的 SQL 语句
     * @param cmdParams SQL 语句的参数表
     * @return
     */
    public ResultSet getResultSet(Connection conn, String cmdText, Object... cmdParams) {
        logger.info(cmdText, cmdParams);
        PreparedStatement pstmt = getPreparedStatement(conn, cmdText, cmdParams);
        if (pstmt == null) {
            return null;
        }
        try {
            return pstmt.executeQuery();
        } catch (SQLException ex) {
            logger.error(cmdText, ex);
            closeObject(pstmt);
        }
        return null;
    }

    public Object buildScalar(ResultSet rs) {
        if (rs == null) {
            return null;
        }
        Object obj = null;
        try {
            if (rs.next()) {
                obj = rs.getObject(1);
            }
        } catch (SQLException ex) {
            logger.error(null, ex);
        }
        return obj;
    }

    /**
     * 关闭
     *
     * @param obj
     */
    public void close(Object obj) {
        if (obj == null) {
            return;
        }
        try {
            if (obj instanceof Statement) {
                Connection connection = ((Statement) obj).getConnection();
                ((Statement) obj).close();
                connection.close();
            } else if (obj instanceof PreparedStatement) {
                Connection connection = ((PreparedStatement) obj).getConnection();
                ((PreparedStatement) obj).close();
                connection.close();
            } else if (obj instanceof ResultSet) {
                Connection connection = ((ResultSet) obj).getStatement().getConnection();
                Statement statement = ((ResultSet) obj).getStatement();
                ((ResultSet) obj).close();
                statement.close();
                connection.close();
            } else if (obj instanceof Connection) {
                ((Connection) obj).close();
            }
        } catch (SQLException ex) {
            logger.error(null, ex);
        }
    }

    private void closeObject(Object obj) {
        if (obj == null) {
            return;
        }
        try {
            if (obj instanceof Statement) {
                ((Statement) obj).close();
            } else if (obj instanceof PreparedStatement) {
                ((PreparedStatement) obj).close();
            } else if (obj instanceof ResultSet) {
                ((ResultSet) obj).close();
            } else if (obj instanceof Connection) {
                ((Connection) obj).close();
            }
        } catch (SQLException ex) {
            logger.error(null, ex);
        }
    }

    @SuppressWarnings("unused")
    private void closeObjectEx(Object obj) {
        if (obj == null) {
            return;
        }
        try {
            if (obj instanceof Statement) {
                ((Statement) obj).close();
            } else if (obj instanceof PreparedStatement) {
                ((PreparedStatement) obj).close();
            } else if (obj instanceof ResultSet) {
                ((ResultSet) obj).getStatement().close();
            } else if (obj instanceof Connection) {
                ((Connection) obj).close();
            }
        } catch (SQLException ex) {
            logger.error(null, ex);
        }
    }

    private void closeConnection(Object obj) {
        if (obj == null) {
            return;
        }
        try {
            if (obj instanceof Statement) {
                ((Statement) obj).getConnection().close();
            } else if (obj instanceof PreparedStatement) {
                ((PreparedStatement) obj).getConnection().close();
            } else if (obj instanceof ResultSet) {
                ((ResultSet) obj).getStatement().getConnection().close();
            } else if (obj instanceof Connection) {
                ((Connection) obj).close();
            }
        } catch (SQLException ex) {
            logger.error(null, ex);
        }
    }

}
